import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
import { Line3 } from "three";

import {
  CSS2DObject,
  CSS2DRenderer,
} from "three/examples/jsm/renderers/CSS2DRenderer.js";

import {
  CSS3DObject,
  CSS3DRenderer,
} from "three/examples/jsm/renderers/CSS3DRenderer.js";

var scene, camera, renderer, renderer2, labelRenderer;
var hUnit = 10;
var mUnit = 1000000
export default {
  data() {
    return {
      _borderData: [], // 楼房基础数据
      _bounds: [], // 楼房四至
      _center: [], // 楼房中心点
      colors: {
        1: 0xff3333,
        2: 0xff3333,
        3: 0xff3333,
        4: 0xff3333,
        5: 0xff3333,
        6: 0xff3333,
        7: 0xffcc33,
        8: 0xffffff,
        9: 0xffffff,
        10: 0xffffff,
      },
    };
  },
  methods: {
    // 创建场景
    initContainer(borderData) {
      /*创建场景对象Scene*/
      scene = new THREE.Scene();
      scene.rotation.set(-45, 0, 0)
      this.initLight()
      this.initCamera()

      this.render();

      //let clock = new THREE.Clock(); //用于更新轨道控制器

      //创建平面
      this.createPlane()

      // 添加楼房楼层平面

      this.addFloors(borderData);

      console.log(scene)
      this.animate();
    },
    createPlane() {
      const geometry = new THREE.PlaneGeometry(10000, 10000);
      const material = new THREE.MeshBasicMaterial({
        color: 0xd9e6ec,
        side: THREE.DoubleSide
      });
      const plane = new THREE.Mesh(geometry, material);
      //plane.position.set(0, 0, 0);

      scene.add(plane);
      plane.receiveShadow = true; // 平面将接收阴影  
      plane.castShadow = true;    // 平面将投射阴影  
    },
    /* 光源设置*/
    initLight() {



      //辅助观察的坐标系
      const axesHelper = new THREE.AxesHelper(100);
      scene.add(axesHelper);


      //光源设置
      const ambient = new THREE.AmbientLight(0xffffff, 0.4);
      scene.add(ambient);
      const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
      directionalLight.position.set(2000, -2000, -100);
      scene.add(directionalLight);//平行光

      // 设置产生阴影的光源对象,开启光源阴影的计算功能
      directionalLight.castShadow = true;

      // console.log('阴影相机属性',directionalLight.shadow.camera);
      // 设置三维场景计算阴影的范围
      directionalLight.shadow.camera.left = -1000;
      directionalLight.shadow.camera.right = 1000;
      directionalLight.shadow.camera.top = 3000;
      directionalLight.shadow.camera.bottom = -2000;
      directionalLight.shadow.camera.near = 0.5;
      directionalLight.shadow.camera.far = 4000;


      // 可视化平行光阴影对应的正投影相机对象
      const cameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
      scene.add(cameraHelper);

      //       // 环境光
      //       var ambientLight = new THREE.AmbientLight(0xffffff);
      //       scene.add(ambientLight);
      //       // 平行光
      //       const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
      //       //平行光设置产生阴影的光源对象, 开启光源阴影的计算功能
      //       directionalLight.castShadow = true;

      //       // 创建点光源，并设置其投射阴影  
      //       var light = new THREE.PointLight(0xffffff, 1, 0);
      //       light.position.set(0, 1000, 1000); // 将光源放置在场景中心  
      //       light.castShadow = true;     // 点光源将投射阴影  
      //       light.shadow.camera.near = 0.5; // 阴影的相机近距离  
      //       light.shadow.camera.far = 5;    // 阴影的相机远距离  
      //       light.shadow.camera.left = -1;  // 阴影的相机左侧边界  
      //       light.shadow.camera.right = 1;  // 阴影的相机右侧边界  
      //       light.shadow.camera.top = 1;    // 阴影的相机顶部边界  
      //       light.shadow.camera.bottom = -1; // 阴影的相机底部边界  
      //       scene.add(light);
    },
    initCamera() {
      /**
       * 相机设置
       */
      var width = window.innerWidth; //窗口宽度
      var height = window.innerHeight; //窗口高度
      var k = width / height; //窗口宽高比
      var s = 1500; //三维场景显示范围控制系数，系数越大，显示的范围越大
      //创建相机对象
      camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        0.1,
        1000000
      );
      camera.position.set(3000, 2000, 3000);
      camera.lookAt(0, 0, 0);
    },


    animate() {
      renderer.render(scene, camera);
      renderer2.render(scene, camera);
      // let delta = clock.getDelta();
      // controls.update(delta);
      requestAnimationFrame(this.animate);
    },

    render() {



      let dom = document.getElementById("modelBox");
      /**
       * 创建渲染器对象
       */
      renderer = new THREE.WebGLRenderer({
        antialias: true,
      });
      renderer.setPixelRatio(window.devicePixelRatio); //防止输出模糊
      renderer.setSize(window.innerWidth, window.innerHeight);
      dom.appendChild(renderer.domElement);
      renderer.setClearColor(new THREE.Color(0xcce0ff))
      renderer.shadowMap.enabled = true;

      var controls = new OrbitControls(camera, renderer.domElement);
      controls.target = new THREE.Vector3(0, 0, 0); //控制焦点
      controls.autoRotate = false; //将自动旋转关闭

      //设置dom元素的渲染
      renderer2 = new CSS3DRenderer();
      renderer2.setSize(window.innerWidth, window.innerHeight);
      renderer2.domElement.style.position = "absolute";
      renderer2.domElement.style.top = 0;
      dom.appendChild(renderer2.domElement);
      var controls2 = new OrbitControls(camera, renderer2.domElement);
      controls2.target = new THREE.Vector3(0, 0, 0); //控制焦点
      controls2.autoRotate = false; //将自动旋转关闭
    },
    // 添加楼群
    addFloors(data) {
      // 数据处理/基础数据计算
      this._dataAnalysis(data);
      this._getModelBounds();
      this._getModelCenter();
      this._dataAnalysisAll();

      // 添加楼层
      this._borderData.forEach((res) => {
        if (res.type === "building") {
          this.createFloor(res);
        }
        // else if (res.type === "road") {
        //   console.log("进入road");
        //   this.createRoad(res);
        // } else if (res.type === "peitao") {
        //   this.createPeitao(res);
        // } else if (res.geometryType === "MultiLineString") {
        //   console.log(res);
        //   this.createHouseLine(res);
        // }
      });
    },
    //创建路的平面
    createRoadShape(data) {
      var shape = new THREE.Shape();
      data.map((item, index) => {
        if (index === 0) {
          item.forEach((e, i) => {
            if (i === 0) {
              shape.moveTo(...e);
            } else {
              shape.lineTo(...e);
            }
          });
        } else {
          const path = new THREE.Path();
          item.forEach((e, i) => {
            if (i === 0) {
              path.moveTo(...e);
            } else {
              path.lineTo(...e);
            }
          });
          shape.holes.push(path);
        }
      });

      return shape;
    },
    //添加线
    createHouseLine(data) {
      var group = new THREE.Group();
      // group.rotation.set(-1.6, 0, 0);
      scene.add(group);
      if (data.points) {
        const points = [];
        var pos1 = null;
        var pos2 = null;
        data.points.map((item, index) => {
          if (index === 0) {
            pos1 = new THREE.Vector3(item[0], item[1], 0);
          } else if (index === 1) {
            pos2 = new THREE.Vector3(item[0], item[1], 0);
          }
          points.push(new THREE.Vector3(item[0], item[1], 0));
        });
        const material = new THREE.LineBasicMaterial({ color: 0x3f96f1 });
        const geometry = new THREE.BufferGeometry().setFromPoints(points);
        const line = new THREE.Line(geometry, material);
        group.add(line);

        var distance = pos1.distanceTo(pos2).toFixed(0) * 1;
        console.log(distance);
        var center = new THREE.Vector3();
        var linePath = new Line3(pos1, pos2);
        linePath.getCenter(center);
        this.addLineText(group, distance + "", center);
      }
    },
    //添加楼间线段文字

    //添加标注
    addLineText(group, distance, center) {
      const element = document.createElement("div");
      var fontSize = 16;
      element.className = "distance";
      element.innerText = `${distance}`;
      const object = new CSS3DObject(element);
      object.position.x = center.x - (distance.length * fontSize) / 2;
      object.position.y = center.y;
      object.position.z = center.z;
      group.add(object);
      // //object.visible = true;
      // //缩放比例
      // object.scale.set(2, 2, 2);
      // //指定摆放位置
      // object.position.copy(center);
      // object.rotation.y = 0;
      // object.rotation.z = 0;
      // object.rotation.x = Math.PI / 2;
      // group.add(object);

      // var fontSize = 16;
      // var loader = new FontLoader();
      // loader.load(
      //   "http://192.168.10.44:8082/gentilis_regular.typeface.json",
      //   function (font) {
      //     const geometry = new TextGeometry(distance, {
      //       font,
      //       size: fontSize,
      //       height: 1,
      //       curveSegments: 11,
      //       bevelEnabled: true,
      //       bevelThickness: 0.1,
      //       bevelSize: 1,
      //       bevelSegments: 1,
      //     });
      //     var materials = new THREE.MeshBasicMaterial({
      //       color: 0xffffff,
      //     }); // front
      //     var textMesh = new THREE.Mesh(geometry, materials);
      //     textMesh.position.x = center.x - (distance.length * fontSize) / 2;
      //     textMesh.position.y = center.y;
      //     textMesh.position.z = center.z;
      //     group.add(textMesh);
      //   }
      // );
    },
    //添加配套
    createPeitao(data) {
      var group = new THREE.Group();
      //group.rotation.set(-1.6, 0, 0);
      scene.add(group);
      let shape = this.createShape(data.points[0]);
      for (let i = 0; i < data.floor; i++) {
        let mesh = this.createPolyline(shape, i, data.high, 1, 0xffffff);
        group.add(mesh);
      }
    },
    //添加路面
    createRoad(data) {
      var group = new THREE.Group();
      //group.rotation.set(-1.6, 0, 0);
      scene.add(group);
      let shape = this.createRoadShape(data.points);
      var geometry = new THREE.ShapeGeometry(shape);
      var cubeMaterial = new THREE.MeshBasicMaterial({
        color: 0xededed,
        // transparent: true,
        opacity: 1,
        side: THREE.DoubleSide, // 强制双面
      });
      let mesh = new THREE.Mesh(geometry, cubeMaterial);
      mesh.position.z = 0;
      // 设置接收阴影的投影面
      mesh.receiveShadow = true;
      // mesh.scale.set(1,1,1);
      // mesh.scale.set(1, 1, 1);
      // mesh.rotation.set(0, 0, 0);
      group.add(mesh);
    },
    // 添加单个楼
    createFloor(data) {
      // 新建楼房组
      var group = new THREE.Group();
      //group.rotation.set(-1.6, 0, 0);
      scene.add(group);
      let shape = this.createShape(data.points[0]);
      for (let i = 0; i < data.floor; i++) {
        let mesh = this.createPolyline(
          shape,
          i,
          data.high,
          1,
          this.colors[parseInt(data.sun_q1.split(",")[i])]
        );
        mesh.castShadow = true;
        // 设置接收阴影的投影面
        mesh.receiveShadow = true;
        group.add(mesh);
      }
      if (group.children[0]) {
        var center = this.getCenterPoint(group.children[0]);
        center.z = (data.floor + 1) * data.high * hUnit;
        const element = document.createElement("div");
        element.className = "tag";
        element.innerText = `${data.building_n}`;
        const object = new CSS3DObject(element);
        //object.visible = true;
        //缩放比例
        object.scale.set(2, 2, 2);
        //指定摆放位置
        object.position.copy(center);
        object.rotation.y = 0;
        object.rotation.z = 0;
        object.rotation.x = Math.PI / 2;
        group.add(object);
      }
    },
    //获取楼栋中点
    getCenterPoint(mesh) {
      var middle = new THREE.Vector3();
      var geometry = mesh.geometry;

      geometry.computeBoundingBox();

      middle.x = (geometry.boundingBox.max.x + geometry.boundingBox.min.x) / 2;
      middle.y = (geometry.boundingBox.max.y + geometry.boundingBox.min.y) / 2;
      middle.z = (geometry.boundingBox.max.z + geometry.boundingBox.min.z) / 2;

      return middle;
    },
    // 数据转换
    _dataAnalysis(borderData) {
      let data = [];
      borderData.features.forEach((res) => {
        if (
          res.geometry.type === "polygon" ||
          res.geometry.type === "MultiLineString"
        ) {
          res.geometry.coordinates.forEach((r) => {
            // 将度转换为米
            r = r.map((re) => {
              return [
                (re[0] * mUnit).toFixed(0) * 1,
                (re[1] * mUnit).toFixed(0) * 1,
              ];
            });
            data.push({
              ...res.properties,
              geometryType: res.geometry.type,
              points: r,
            });
          });
        } else if (res.geometry.type === "MultiPolygon") {
          let pointArrs = [];
          res.geometry.coordinates.forEach((r) => {
            // 将度转换为米
            r.map((re) => {
              let pr = [];
              re.map((ree) => {
                // console.log(ree[0]);
                pr.push([
                  (ree[0] * mUnit).toFixed(0) * 1,
                  (ree[1] * mUnit).toFixed(0) * 1,
                ]);
              });
              pointArrs.push(pr);
            });
          });
          data.push({
            ...res.properties,
            geometryType: res.geometry.type,
            points: pointArrs,
          });
        }
      });
      this._borderData = data;
    },
    // 获取模型四至
    _getModelBounds() {
      // 四至： 上右下左
      let bounds = [0, 0, 0, 0];
      // 所有点数组
      let pointArr = [];
      // 所有点经度数组
      let pointLonArr = [];
      // 所有点纬度数组
      let pointLatArr = [];
      // 获取所有点数组
      this._borderData.forEach((res) => {
        if (
          res.geometryType === "polygon" ||
          res.geometryType === "MultiLineString"
        ) {
          pointArr = pointArr.concat(res.points);
        } else if (res.geometryType === "MultiPolygon") {
          res.points.map((item) => {
            pointArr = pointArr.concat(item);
          });
        }
      });
      // 获取经度、纬度数组
      pointArr.forEach((res) => {
        pointLonArr.push(res[0]);
        pointLatArr.push(res[1]);
      });
      // 获取四至
      bounds = [
        Math.max(...pointLatArr),
        Math.min(...pointLonArr),
        Math.min(...pointLatArr),
        Math.max(...pointLonArr),
      ];
      this._bounds = bounds;
    },
    // 获取模型中心点
    _getModelCenter() {
      let center = [
        (this._bounds[1] + this._bounds[3]) / 2,
        (this._bounds[0] + this._bounds[2]) / 2,
      ];
      this._center = center;
    },
    // 数据转换2-将数据移动至原点
    _dataAnalysisAll() {
      this._borderData.forEach((res) => {
        if (
          res.geometryType === "polygon" ||
          res.geometryType === "MultiLineString"
        ) {
          res.points.forEach((re) => {
            re[0] = re[0] - this._center[0];
            re[1] = re[1] - this._center[1];
          });
        } else if (res.geometryType === "MultiPolygon") {
          res.points.forEach((re) => {
            re.map((ree) => {
              ree[0] = ree[0] - this._center[0];
              ree[1] = ree[1] - this._center[1];
            });
          });
        }
      });
    },
    // 创建平面集合
    createShape(data) {
      var shape = new THREE.Shape();
      data.forEach((e, i) => {
        if (i === 0) {
          shape.moveTo(...e);
        } else {
          shape.lineTo(...e);
        }
      });
      return shape;
    },
    // 创建透明平面
    createPolyline(shape, h, high, opacity = 1, color = "rgb(255, 255,255)") {
      // var shape = new THREE.ShapeGeometry(shape);
      var geometry = new THREE.ExtrudeGeometry(shape, {
        depth: high * hUnit,
      });
      var cubeMaterial = new THREE.MeshBasicMaterial({
        color: color,
        // transparent: true,
        opacity: opacity,
        side: THREE.DoubleSide, // 强制双面
      });
      var mesh = new THREE.Mesh(geometry, cubeMaterial);

      mesh.position.z = h * high * hUnit;
      // mesh.scale.set(1,1,1);
      // mesh.scale.set(1, 1, 1);
      // mesh.rotation.set(0, 0, 0);
      // 长方体作为EdgesGeometry参数创建一个新的几何体
      const edges = new THREE.EdgesGeometry(geometry);
      const edgesMaterial = new THREE.LineBasicMaterial({
        color: 0xcccccc,
      });
      const line = new THREE.LineSegments(edges, edgesMaterial);
      mesh.add(line);
      return mesh;
    },
  },
};
